﻿// Copyright (c) 2008 Paul Schaeflein
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in 
// the Software without restriction, including without limitation the rights to use, 
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
// Software, and to permit persons to whom the Software is furnished to do so, subject 
// to the following conditions:

// The above copyright notice and this permission notice shall be included in all 
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  

using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

using Microsoft.SharePoint;
using System.Collections.Generic;

namespace Schaeflein.Community.WebParts
{

  public class ImageUpload : System.Web.UI.WebControls.WebParts.WebPart
  {

    #region Custom Properties

    private string imageUrl;
    public string ImageUrl
    {
      get { return imageUrl; }
      set { imageUrl = value; }
    }

    private string imageAltText;
    public string ImageAltText
    {
      get { return imageAltText; }
      set { imageAltText = value; }
    }

    private string imageHeight;
    public string ImageHeight
    {
      get { return imageHeight; }
      set { imageHeight = value; }
    }

    private string imageWidth;
    public string ImageWidth
    {
      get { return imageWidth; }
      set { imageWidth = value; }
    }

    #endregion

    #region Private Variables

    private const string TRACE_CLASS_ID = "ImageUpload";
    private bool imagePosted = false;
    private List<string> validFileTypes = new List<string>();

    private HtmlInputFile fileUpload;
    private HtmlInputFile FileUpload
    {
      get
      {
        EnsureChildControls();
        return fileUpload;
      }
    }

    private Label errorMessage;
    private Label ErrorMessage
    {
      get
      {
        EnsureChildControls();
        return errorMessage;
      }
    }


    #endregion

    #region WebPart Overrides

    protected override void OnLoad(EventArgs e)
    {
      base.OnLoad(e);

      validFileTypes.Add(".bmp");
      validFileTypes.Add(".jpg");
      validFileTypes.Add(".gif");
      validFileTypes.Add(".png");
    }

    protected override void CreateChildControls()
    {
      base.CreateChildControls();

      string TRACE_CATEGORY = TRACE_CLASS_ID + "_CreateChildControls";

      try
      {
        // get the "image" library
        string docLibPath = System.Web.Configuration.WebConfigurationManager.AppSettings["Schaeflein.Community.WebParts.ImageUpload"];
        if (String.IsNullOrEmpty(docLibPath))
        {
          Context.Trace.Write(TRACE_CATEGORY, "doc lib not set");

          string message = "The Image Upload part will upload and display images. The images must be stored in a ";
          message += "Document Library or Picture Library.<br><br>";
          message += "The URL of this library must be configured in the web.config file.  Run the <i>STSADM&nbsp;-o&nbsp;SetImageUploadLocation</i>";
          message += " command to set the location.";

          HtmlGenericControl div = new HtmlGenericControl("div");
          div.Attributes.Add("class", "UserGeneric");

          Label msgLabel = new Label();
          msgLabel.Text = message;
          div.Controls.Add(msgLabel);

          Controls.Add(div);

          return;
        }


        if (String.IsNullOrEmpty(this.ImageUrl))
        {
          HtmlGenericControl div = null;

          Context.Trace.Write(TRACE_CATEGORY, "no image stored");
          string instructions = "The Image Upload part will upload and then display the selected image.<br><br>";
          instructions += "No image has yet been uploaded. Please select and upload the image and provide alternate text.";

          div = new HtmlGenericControl("div");
          div.Attributes.Add("class", "UserGeneric");

          Label insLabel = new Label();
          insLabel.Text = instructions;
          div.Controls.Add(insLabel);
          Controls.Add(div);

          div = Helpers.CreateUserSectionHead();
          div.Controls.Add(new LiteralControl("Image Url:<br/>&nbsp;&nbsp;"));
          fileUpload = new HtmlInputFile();
          fileUpload.ID = "fileUpload";
          div.Controls.Add(fileUpload);
          Controls.Add(div);

          div = Helpers.CreateUserSectionHead();
          div.Controls.Add(new LiteralControl("Alternate text:<br/>&nbsp;&nbsp;"));
          div.Controls.Add(Helpers.CreateTextBox("alternateText"));
          Controls.Add(div);

          div = Helpers.CreateUserSectionHead();
          div.Controls.Add(new LiteralControl("Image Height (optional):<br/>&nbsp;&nbsp;"));
          div.Controls.Add(Helpers.CreateTextBox("imageHeight", 35));
          Controls.Add(div);

          div = Helpers.CreateUserSectionHead();
          div.Controls.Add(new LiteralControl("Image Width (optional):<br/>&nbsp;&nbsp;"));
          div.Controls.Add(Helpers.CreateTextBox("imageWidth", 35));
          Controls.Add(div);

          div = Helpers.CreateUserSectionHead();
          Button saveBtn = new Button();
          saveBtn.ID = "imageSave";
          saveBtn.Text = " Save ";
          saveBtn.Click += new EventHandler(saveBtn_Click);
          div.Controls.Add(saveBtn);
          Controls.Add(div);

          errorMessage = new Label();
          errorMessage.ID = "errorMessage";
          errorMessage.CssClass = "ms-ToolPaneError";
          Controls.Add(errorMessage);

        }
        else
        {
          Context.Trace.Write(TRACE_CATEGORY, "rendering image");
          //wrap the image so it gets the right css 
          HtmlGenericControl div = new HtmlGenericControl("div");
          div.Attributes.Add("class", "UserGeneric");

          Image img = new Image();
          img.ImageUrl = this.ImageUrl;
          img.BorderWidth = new Unit(0);
          img.AlternateText = this.ImageAltText;

          int intVal = 0;
          if (Int32.TryParse(this.ImageHeight, out intVal))
          {
            img.Height = new Unit(intVal);
          }
          if (Int32.TryParse(this.ImageWidth, out intVal))
          {
            img.Width = new Unit(intVal);
          }
          div.Controls.Add(img);
          Controls.Add(div);
        }
      }
      catch (Exception ex)
      {
        Context.Trace.Warn(TRACE_CATEGORY, ex.ToString());
      }
    }

    protected override void OnPreRender(EventArgs e)
    {
      string TRACE_CATEGORY = TRACE_CLASS_ID + "_PreRender";

      try
      {
        Context.Trace.Write(TRACE_CATEGORY, "imagePosted: " + imagePosted.ToString());

        // If an image was upload on this postback, then remove the form and output only the image.
        if (imagePosted)
        {
          Controls.Clear();
          CreateChildControls();
        }
      }
      catch (Exception ex)
      {
        Context.Trace.Warn(TRACE_CATEGORY, ex.ToString());
      }
    }

    public override EditorPartCollection CreateEditorParts()
    {
      ArrayList editorArray = new ArrayList();
      ImageUploadEditor editor = new ImageUploadEditor();
      editor.ID = this.ID + "_editorPart1";
      editorArray.Add(editor);
      EditorPartCollection editorParts = new EditorPartCollection(editorArray);
      return editorParts;
    }

    #endregion

    #region Private helper methods

    void saveBtn_Click(object sender, EventArgs e)
    {
      string TRACE_CATEGORY = TRACE_CLASS_ID + "_SaveButton_OnClick";

      try
      {
        // make sure that something was actually posted.
        if (fileUpload.PostedFile != null && fileUpload.PostedFile.ContentLength > 0)
        {
          Context.Trace.Write(TRACE_CATEGORY, "PostedFile.FileName : " + fileUpload.PostedFile.FileName);
          Context.Trace.Write(TRACE_CATEGORY, "PostedFile.ContentLength : " + fileUpload.PostedFile.ContentLength.ToString());

          // only accept valid image files
          string filetype = System.IO.Path.GetExtension(fileUpload.PostedFile.FileName);
          if (!validFileTypes.Contains(filetype))
          {
            errorMessage.Text = "Only image file types are allowed.";
            return;
          }

          TextBox altText = this.FindControl("alternateText") as TextBox;
          this.ImageAltText = altText.Text;
          TextBox widText = this.FindControl("imageWidth") as TextBox;
          this.ImageWidth = widText.Text;
          TextBox hgtText = this.FindControl("imageHeight") as TextBox;
          this.ImageHeight = hgtText.Text;

          // The destination library may be in a different site. So, let's force the validation
          // now while it will still be valid. Then, the cached validation will be used in the
          // elevated method.
          Microsoft.SharePoint.Utilities.SPUtility.ValidateFormDigest();

          SPSecurity.CodeToRunElevated processingCode = new SPSecurity.CodeToRunElevated(ProcessPostedFile);
          SPSecurity.RunWithElevatedPrivileges(processingCode);
        }
      }
      catch (Exception ex)
      {
        Context.Trace.Warn(TRACE_CATEGORY, ex.ToString());
      }
    }

    private void ProcessPostedFile()
    {
      string TRACE_CATEGORY = TRACE_CLASS_ID + "_ProcessPostedFile";

      try
      {
        // get the filename and stream
        string fn = System.IO.Path.GetFileName(fileUpload.PostedFile.FileName);
        Context.Trace.Write(TRACE_CATEGORY, "filename: " + fn);
        System.IO.Stream stm = fileUpload.PostedFile.InputStream;
        byte[] contents = new byte[stm.Length];

        stm.Read(contents, 0, (int)stm.Length);
        stm.Close();
        Context.Trace.Write(TRACE_CATEGORY, "buffer length: " + contents.GetUpperBound(0).ToString());

        // get the "image" library
        string docLibPath = System.Web.Configuration.WebConfigurationManager.AppSettings["Schaeflein.Community.WebParts.ImageUpload"];
        Context.Trace.Write(TRACE_CATEGORY, "docLibPath: " + docLibPath);
        // first, get the site containing the image library
        using (SPSite site = new SPSite(docLibPath))
        {
          Context.Trace.Write(TRACE_CATEGORY, "site: " + site.Url);
          using (SPWeb web = site.OpenWeb())
          {
            Context.Trace.Write(TRACE_CATEGORY, "web: " + web.Url);
            SPFolder docFolder = web.GetFolder(docLibPath);
            Context.Trace.Write(TRACE_CATEGORY, "got folder");

            // delete the file if it exists
            SPFile imageFile = null;
            try
            {
              imageFile = docFolder.Files[fn];
              Context.Trace.Write(TRACE_CATEGORY, "got file");
            }
            catch
            {
              Context.Trace.Write(TRACE_CATEGORY, "file does not exist");
            }
            if (imageFile != null)
            {
              Context.Trace.Write(TRACE_CATEGORY, "deleting file");
              docFolder.Files.Delete(fn);
            }

            // save the file
            Context.Trace.Write(TRACE_CATEGORY, "saving file");
            imageFile = docFolder.Files.Add(fn, contents);

            // set the Url of the image
            this.ImageUrl = docLibPath + "/" + fn;
            this.SetPersonalizationDirty();

            imagePosted = true;
          }
        }
      }
      catch (Exception ex)
      {
        Context.Trace.Warn(TRACE_CATEGORY, ex.ToString());
        Label errorMessage = this.FindControl("errorMessage") as Label;
        if (errorMessage != null)
        {
          errorMessage.Text = ex.Message;
        }
      }
    }

    #endregion
  }
}